package io.adrainty.bolee.framework.mybatis.configuration;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import io.adrainty.bolee.framework.commons.properties.SnowflakeProperties;
import io.adrainty.bolee.framework.commons.user.SubjectContentUtil;
import io.adrainty.bolee.framework.mybatis.constants.MybatisPlusConstant;
import io.adrainty.bolee.framework.mybatis.handler.AutoMetaObjectHandler;
import io.adrainty.bolee.framework.mybatis.handler.DeptNoLineHandler;
import io.adrainty.bolee.framework.mybatis.handler.PersonLineHandler;
import io.adrainty.bolee.framework.mybatis.interceptor.DeptNoLineInnerInterceptor;
import io.adrainty.bolee.framework.mybatis.interceptor.PersonLineInnerInterceptor;
import io.adrainty.bolee.framework.mybatis.properties.TenantProperties;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.StringValue;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.util.List;
import java.util.Objects;

/**
 * @author adrainty
 * @version v1.0.0
 * @since 2025/6/12 下午4:30
 */

@Slf4j
@Configuration
@EnableConfigurationProperties({
        TenantProperties.class,
        SnowflakeProperties.class,
})
@ConditionalOnBean(DataSource.class)
public class MybatisPlusConfig {

    @Resource
    private TenantProperties tenantProperties;

    /**
     * 获取主键生成器
     *
     * @return IdentifierGenerator
     */
    @Bean
    public IdentifierGenerator identifierGenerator(SnowflakeProperties properties) {
        if (ObjectUtil.isAllNotEmpty(properties.getWorkerId(), properties.getDatacenterId())) {
            return new DefaultIdentifierGenerator(properties.getWorkerId(), properties.getDatacenterId());
        }
        return DefaultIdentifierGenerator.getInstance();
    }

    /**
     * 自动填充
     *
     * @return MetaObjectHandler
     */
    @Bean
    @ConditionalOnMissingBean
    public MetaObjectHandler myMetaObjectHandler() {
        return new AutoMetaObjectHandler();
    }

    /**
     * 新的分页插件,一缓和二缓遵循mybatis的规则, 需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 如果用了分页插件注意
        // 先 add TenantLineInnerInterceptor
        // 再 add PaginationInnerInterceptor
        // 用了分页插件必须设置 MybatisConfiguration#useDeprecatedExecutor = false
        //多租户租插件
        interceptor.addInnerInterceptor(companyNoInterceptor());
        //数据权限-部门插件
        interceptor.addInnerInterceptor(deptNoLineInnerInterceptor());
        //数据权限-本人插件
        interceptor.addInnerInterceptor(personLineInnerInterceptor());
        //分页的插件
        interceptor.addInnerInterceptor(paginationInnerInterceptor());
        return interceptor;
    }

    @Bean
    public TenantLineInnerInterceptor companyNoInterceptor() {
        return new TenantLineInnerInterceptor(new TenantLineHandler() {

            @Override
            public Expression getTenantId() {
                //从当前的SubjectContent上下文中获取用户信息CompanyNo
                String companyNo = SubjectContentUtil.getCompanyNo();
                return companyNo == null ? null : new StringValue(companyNo);
            }

            @Override
            public String getTenantIdColumn() {
                return MybatisPlusConstant.COMPANY_NO;
            }

            @Override
            public boolean ignoreTable(String tableName) {
                // 如果当前为默认管理平台则忽略表
                // 如果tableName出现在忽略配置中则不添加企业查询条件
                List<String> tableNameList = tenantProperties.getIgnoreCompanyTables();
                if (CollUtil.isNotEmpty(tableNameList) && tableNameList.contains(tableName)) {
                    return true;
                }
                //如果查询字段值为空则不添加企业查询条件
                Expression tenantId = this.getTenantId();
                return Objects.isNull(tenantId);
            }
        });
    }

    @Bean
    public PersonLineInnerInterceptor personLineInnerInterceptor() {
        return new PersonLineInnerInterceptor(new PersonLineHandler() {
            @Override
            public Expression getCreateBy() {
                if (Objects.isNull(SubjectContentUtil.getUserVO())) {
                    return null;
                }
                if (Objects.isNull(SubjectContentUtil.getUserVO().getDataSecurityVO())) {
                    return null;
                }
                Boolean yourselfData = SubjectContentUtil.getUserVO().getDataSecurityVO().getYourselfData();
                Long userId = SubjectContentUtil.getUserVO().getId();
                return Boolean.TRUE.equals(yourselfData) ? new StringValue(String.valueOf(userId)) : null;
            }

            @Override
            public String getCreateByColumn() {
                return PersonLineHandler.super.getCreateByColumn();
            }

            @Override
            public boolean ignoreTable(String tableName) {
                //如果未指定创建人
                Expression expression = this.getCreateBy();
                if (Objects.isNull(expression)) {
                    return true;
                }
                //如果tableName出现在忽略配置中则不添加数据权限
                List<String> tableNameList = tenantProperties.getIgnoreDataSecurityTables();
                return CollUtil.contains(tableNameList, tableName);
            }
        });
    }

    @Bean
    public DeptNoLineInnerInterceptor deptNoLineInnerInterceptor() {
        return new DeptNoLineInnerInterceptor(new DeptNoLineHandler() {
            @Override
            public ExpressionList<StringValue> getDeptNoList() {
                if (Objects.isNull(SubjectContentUtil.getUserVO())) {
                    return new ExpressionList<>();
                }
                if (Objects.isNull(SubjectContentUtil.getUserVO().getDataSecurityVO())) {
                    return new ExpressionList<>();
                }
                List<String> deptNos = SubjectContentUtil.getUserVO().getDataSecurityVO().getDeptNos();
                return CollUtil.isEmpty(deptNos) ? null : new ExpressionList<>(
                        deptNos.stream().map(StringValue::new).toList());
            }

            @Override
            public String getDeptNoColumn() {
                return DeptNoLineHandler.super.getDeptNoColumn();
            }

            @Override
            public boolean ignoreTable(String tableName) {
                //如果未指定部门列表
                ExpressionList<StringValue> expressionList = this.getDeptNoList();
                if (CollUtil.isEmpty(expressionList)) {
                    return true;
                }
                //如果tableName出现在忽略配置中则不添加数据权限
                List<String> tableNameList = tenantProperties.getIgnoreDataSecurityTables();
                return CollUtil.contains(tableNameList, tableName);
            }
        });
    }


    //分页的插件配置
    @Bean
    public PaginationInnerInterceptor paginationInnerInterceptor() {
        return new PaginationInnerInterceptor(DbType.MYSQL);
    }

}
